import { PureComponent } from 'react';
import {
  Scene, OrthographicCamera, BoxGeometry, Line, Vector3,
  Mesh, WebGLRenderer, DirectionalLight, DoubleSide,
  MeshBasicMaterial, MeshLambertMaterial
} from 'three';
import Stats from 'stats.js';
import OBJLoader from '@/utils/OBJLoader';
import MTLLoader from '@/utils/MTLLoader';
import { requestAnimationFrame } from '@/utils/requestAnimationFrame';

const drawAxes = scene => {
  const xGeo = new BoxGeometry();
  const xGeoPoints = [
    new Vector3(0, 0, 0),
    new Vector3(6, 0, 0)
  ];
  xGeo.setFromPoints(xGeoPoints);
  const xMat = new MeshBasicMaterial({
    color: 0xff0000
  });
  const xAxis = new Line(xGeo, xMat);
  scene.add(xAxis);

  const yGeo = new BoxGeometry();
  const yGeoPoints = [
    new Vector3(0, 0, 0),
    new Vector3(0, 6, 0)
  ];
  yGeo.setFromPoints(yGeoPoints);
  const yMat = new MeshBasicMaterial({
    color: 0x00ff00
  });
  const yAxis = new Line(yGeo, yMat);
  scene.add(yAxis);

  const zGeo = new BoxGeometry();
  const zGeoPoints = [
    new Vector3(0, 0, 0),
    new Vector3(0, 0, 6)
  ];
  zGeo.setFromPoints(zGeoPoints);
  const zMat = new MeshBasicMaterial({
    color: 0x00ccff
  });
  const zAxis = new Line(zGeo, zMat);
  scene.add(zAxis);
};

const scene = new Scene();

drawAxes(scene);

const camera = new OrthographicCamera(-5, 5, 3.75, -3.75, 0.1, 100);
camera.position.set(15, 25, 25);
camera.lookAt(0, 2, 0);

const light = new DirectionalLight(0xffffff);
light.position.set(20, 10, 5);
scene.add(light);

let mesh = null;

let renderer = null;

let animateId = 0;

const stats = new Stats();

const animate = () => {
  stats.begin();

  mesh.rotation.y += 0.01;

  if(mesh.rotation.y > 2 * Math.PI) {
    mesh.rotation.y -= 2 * Math.PI;
  }

  stats.end();
  renderer.render(scene, camera);
  animateId = requestAnimationFrame(animate);
};

const startAnimate = () => {
  if(animateId) return;
  animateId = requestAnimationFrame(animate);
};

const stopAnimate = () => {
  if(!animateId) return;
  cancelAnimationFrame(animateId);
  animateId = 0;
};

class Index extends PureComponent {

  componentDidMount() {
    renderer = new WebGLRenderer({
      canvas: document.getElementById('mainCanvas')
    });

    const fpsContainer = document.getElementById('fps-container');
    stats.domElement.style.position = '';
    fpsContainer.appendChild(stats.dom);

    //加载材质
    const mtlLoader = new MTLLoader();
    mtlLoader.setPath('/models'); //设置路径前缀
    mtlLoader.load('/port.mtl', material => {
      /**
       * 羡辙的demo中这里有个预加载的处理, 因为我是按照自己的思路来的
       * 所以这里没有写那个预加载的代码, 暂时没找到这么写的原因
       * 个人推测可能是居于性能考虑
       */
      // material.preload();
      
      //加载模型
      const objLoader = new OBJLoader();
      objLoader.setMaterials(material); //这才是设置材质的标准姿势
      objLoader.setPath('/models'); //设置路径前缀
      objLoader.load('/port.obj', obj => {
        // obj.material = material; 这样设置材质是不行的
        /**
         * 羡辙的demo中这里调整了obj的位置
         * 同时使用了另一种方式将其添加到场景中
         * 我这里由于前面学过这个方式, 就使用了这个方式,
         * 效果是一样的, 同时还让它双面都渲染了
         */
        //让他双面都绘制
        obj.traverse(child => {
          if(child instanceof Mesh) {
            child.material.side = DoubleSide;
          }
        });

        mesh = obj;
        scene.add(obj);
        renderer.render(scene, camera);
      });
    });
  }

  render() {

    return (
      <div>
        <div>
          <button
            onClick={startAnimate}
          >开始</button>
          <button
            onClick={stopAnimate}
          >停止</button>
        </div>
        <div
          id="fps-container"
          style={{
            display: 'flex',
            padding: '5px'
          }}
        />
        <canvas
          id="mainCanvas"
          width="400"
          height="300"
        />
      </div>
    );
  }

}

export default Index;